//
//  CGRect+Layout.swift
//  PMS
//
//  Created by 何海涛 on 15/11/4.
//  Copyright © 2015年 途家. All rights reserved.
//

import UIKit

public func + (lhs : CGPoint, rhs : CGPoint) -> CGPoint {
    return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}

public func - (lhs : CGPoint, rhs : CGPoint) -> CGPoint {
    return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
}

extension CGRect {
    public func turnLeft() -> CGRect {
        //should define a turn based point
        return CGRect(x: self.origin.x - width, y: self.origin.y, width: width, height: height)
    }
    
    public func turnRight() -> CGRect {
        //should define a turn based point
        return CGRect(x: self.origin.x + width, y: self.origin.y, width: width, height: height)
    }
    
    public func turnUp() -> CGRect {
        //should define a turn based point
        return CGRect(x: self.origin.x, y: self.origin.y - height, width: width, height: height)
    }
    
    public func turnDown() -> CGRect {
        //should define a turn based point
        return CGRect(x: self.origin.x, y: self.origin.y + height, width: width, height: height)
    }
    
    /// Get a translation rect with zero as origin
    public func translationToZero() -> CGRect {
        return CGRect(x: 0, y: 0, width: width, height: height)
    }
    
    /// Get a transform rect with relative origin.
    public func transformTo(_ origin : CGPoint) -> CGRect {
        return CGRect(origin: self.origin - origin, size: self.size)
    }
    
    /// Create rectangle in the center of current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter size : New rectangle size.
    /// - parameter lAlign : Default value is *.Center*.
    /// - parameter vAlign : Default value is *.Center*.
    public func centerRect(_ size : CGSize, hAlign : UIControl.ContentHorizontalAlignment = .center, vAlign : UIControl.ContentVerticalAlignment = .center) -> CGRect {
        var hx, hy : CGFloat
        switch hAlign {
        case .center :
            hx = self.origin.x + (self.width - size.width)/2
        case .left, .leading:
            hx = self.origin.x + self.width/2 - size.width
        case .right, .trailing:
            hx = self.origin.x + self.width/2
        case .fill:
            hx = self.origin.x // an error implement. cannot understand Fill here.
        }
        switch vAlign {
        case .center:
            hy = self.origin.y + (self.height - size.height)/2
        case .top:
            hy = self.origin.y + self.height/2 - size.height
        case .bottom:
            hy = self.origin.y + self.height/2
        case .fill:
            hy = self.origin.y // an error implement. cannot understand Fill here.
        }
        return CGRect(origin: CGPoint(x: hx, y: hy), size: size)
    }
    
    /// Create outer rectangle before current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect right border and current rect left border.
    /// - parameter align : Default value is *.Bottom*.
    public func beforeRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentVerticalAlignment = .bottom) -> CGRect {
        var hy : CGFloat
        switch align {
        case .center:
            hy = self.origin.y + (self.height - size.height)/2
        case .top:
            hy = self.origin.y
        case .bottom:
            hy = self.origin.y + self.height - size.height
        case .fill:
            hy = self.origin.y + self.height/2
        }
        return CGRect(origin: CGPoint(x: origin.x - offset, y: hy), size: size)
    }
    
    /// Create inner rectangle left side of current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect left border and current rect left border.
    /// - parameter align : Default value is *.Bottom*.
    public func leftRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentVerticalAlignment = .bottom) -> CGRect {
        var hy : CGFloat
        switch align {
        case .center:
            hy = self.origin.y + (self.height - size.height)/2
        case .top:
            hy = self.origin.y
        case .bottom:
            hy = self.origin.y + self.height - size.height
        case .fill:
            hy = self.origin.y + self.height/2
        }
        return CGRect(origin: CGPoint(x: origin.x + offset, y: hy), size: size)
    }
    
    
    /// Create outer rectangle after current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect left border and current rect right border.
    /// - parameter align : Default value is *.Bottom*.
    public func afterRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentVerticalAlignment = .bottom) -> CGRect {
        var hy : CGFloat
        switch align {
        case .center:
            hy = self.origin.y + (self.height - size.height)/2
        case .top:
            hy = self.origin.y
        case .bottom:
            hy = self.origin.y + self.height - size.height
        case .fill:
            hy = self.origin.y + self.height/2
        }
        return CGRect(origin: CGPoint(x: origin.x + width + offset, y: hy), size: size)
    }
    
    /// Create inner rectangle right side of current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect right border and current rect right border.
    /// - parameter align : Default value is *.Bottom*.
    public func rightRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentVerticalAlignment = .bottom) -> CGRect {
        var hy : CGFloat
        switch align {
        case .center:
            hy = self.origin.y + (self.height - size.height)/2
        case .top:
            hy = self.origin.y
        case .bottom:
            hy = self.origin.y + self.height - size.height
        case .fill:
            hy = self.origin.y + self.height/2
        }
        return CGRect(origin: CGPoint(x: origin.x + width - size.width - offset, y: hy), size: size)
    }
    
    /// Create outer rectangle above current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect bottom border and current rect top border.
    /// - parameter align : Default value is *.Left*.
    public func aboveRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentHorizontalAlignment = .left) -> CGRect {
        var hx : CGFloat
        switch align {
        case .left, .leading:
            hx = origin.x
        case .center:
            hx = origin.x + (width - size.width)/2
        case .right, .trailing:
            hx = origin.x + width - size.width
        case .fill:
            hx = origin.x + width/2
        }
        return CGRect(origin: CGPoint(x: hx, y: origin.y - offset - size.height), size: size)
    }
    
    /// Create inner rectangle top of current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect top border and current rect top border.
    /// - parameter align : Default value is *.Left*.
    public func topRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentHorizontalAlignment = .left) -> CGRect {
        var hx : CGFloat
        switch align {
        case .left, .leading:
            hx = origin.x
        case .center:
            hx = origin.x + (width - size.width)/2
        case .right, .trailing:
            hx = origin.x + width - size.width
        case .fill:
            hx = origin.x + width/2
        }
        return CGRect(origin: CGPoint(x: hx, y: origin.y + offset), size: size)
    }
    
    /// Create outer rectangle below current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect top border and current rect bottom border.
    /// - parameter align : Default value is *.Left*.
    public func belowRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentHorizontalAlignment = .left) -> CGRect {
        var hx : CGFloat
        switch align {
        case .left, .leading:
            hx = origin.x
        case .center:
            hx = origin.x + (width - size.width)/2
        case .right, .trailing:
            hx = origin.x + width - size.width
        case .fill:
            hx = origin.x + width/2
        }
        return CGRect(origin: CGPoint(x: hx, y: origin.y + height + offset), size: size)
    }
    
    /// Create inner rectangle bottom of current rectangle.
    /// - note : New rectangle and current rectangle are in the same coordinate system.
    /// - parameter offset : Distance between new rect bottom border and current rect bottom border.
    /// - parameter align : Default value is *.Left*.
    public func bottomRect(_ offset : CGFloat, size : CGSize, align : UIControl.ContentHorizontalAlignment = .left) -> CGRect {
        var hx : CGFloat
        switch align {
        case .left, .leading:
            hx = origin.x
        case .center:
            hx = origin.x + (width - size.width)/2
        case .right, .trailing:
            hx = origin.x + width - size.width
        case .fill:
            hx = origin.x + width/2
        }
        return CGRect(origin: CGPoint(x: hx, y: origin.y + height - size.height - offset), size: size)
    }
    
    /// Create equal divide rects.
    public func divideRects(_ count : Int) -> [CGRect] {
        if count < 1 { return [CGRect]() }
        let avg = 1.0/CGFloat(count);
        let avgWeight = Array<CGFloat>(repeating: avg, count: count)
        return divideRects(avgWeight)
    }
    
    /// Create divide by weights
    /// - parameter weights : example : [0.5,0.5] will create 2 equal divide rects both have an width = self.width * 0.5.
    public func divideRects(_ weights : [CGFloat]) -> [CGRect] {
        if weights.count < 1 { return [CGRect]() }
        var startX = self.origin.x
        var result = [CGRect]()
        for item in weights {
            let wid = self.width * item
            result.append(CGRect(x: startX, y: origin.y, width: wid, height: height))
            startX += wid
        }
        return result
    }
}

